home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / printing / lpr2-1.2e / lpr2-1
Text File  |  1995-08-07  |  20KB  |  520 lines

  1. #!/bin/sh
  2.  
  3. # LPR2 -- Utility to print postscript document on both sides.
  4. VERSION='1.2e'
  5.  
  6.  
  7. ######################## LEGAL STUFF, LICENSE, ET AL. #########################
  8.  
  9. # COPYLEFT NOTICE:
  10. # Copyright (c) 1994 Franτois-RenΘ "FarΘ" BΓn Rideau DDa(.ng-Vu~
  11. # (rideau@ens.fr,rideau@frmap711.mathp7.jussieu.fr)
  12.  
  13. # LICENSE AGREEMENT:
  14. #   This program is distributed under *modified* the terms of the
  15. # GNU General Public License (any official version you can find).
  16. #   Particularly,
  17. # 0) You are mostly free to use and redistribute this program.
  18. # 1) there is absolutely NO WARRANTY about what effect it can have
  19. #  on your software or hardware.
  20. # 2) you may strip off any comment or useless characters and statements
  21. #  from this file, but only for personal use. But you shall not distribute
  22. #  a modified or stripped version.
  23. #   Just below are my modifications to the GPL...
  24.  
  25. # SMILEWARE
  26. #   This program is smileware:
  27. # 1) if you use this program several times, if you modify it, or enhance it
  28. #  in any way, you should send me a note, letter, postcard, or even just an
  29. #  e-mail. This note should contain your feedback about your using this
  30. #  program, suggestions about improvements, enhancements, etc, if you have any.
  31. #  But even if you don't, a note/card/etc with just some kind words or a smiley
  32. #  is welcome.
  33. # 2) if you use this program regularly, or reuse it more than three months
  34. #  after you originally used it, I morally bind you to pay for it.
  35. #    The exact amount you pay is up to you, but it shouldn't be less than one
  36. #  hundredth of what a typical commercial program costs near you, and not less
  37. #  than the expenses incurred for paying. Once you determined how much to pay,
  38. #  you should do one of the following with that money:
  39. #  a) give it all to the next beggar you meet (ain't there one just round the
  40. #  corner ?); if you think it's too much money for you to give him, well, 
  41. #  firstly, you're paying for this program, so consider it's me giving your
  42. #  money to the beggar, and second, it will be fun to you to look his reaction.
  43. #  b) if you really don't want to give this money to this beggar, or if there's
  44. #  no beggar where you live, send your money to any charitable or ecological
  45. #  organization you *know* to be honest.
  46. #  c) if you won't give to a beggar, and don't trust any charitable or
  47. #  ecological organization, then send it to me, and I'll do it myself.
  48. #
  49. #   My addresses are at the end of these comments.
  50.  
  51.  
  52. ########################### DESCRIPTION AND HELP #############################
  53.  
  54. # WHAT LPR2 IS MEANT TO BE:
  55. #   To save paper, and lighten you backpack, without lightening your purse by
  56. # buying printers that already print documents on both sides, do use this
  57. # program to print double sided documents.
  58. #   Not throwing away paper is good for just everyone throughout the world.
  59. # Stop the spillage, help save the world, use LPR2 !
  60. #   Enhanced version 1.2 now works with *all* documents I've tried it with !!!
  61.  
  62. # WHAT LPR2 IS *NOT* MEANT TO BE:
  63. #   This program is NOT a full-featured program for manipulating postscript
  64. # documents either. mpage, psutils, and commercial software from Adobe will do
  65. # that for you. However, I've not tried commercial software, but all the free
  66. # utilities I could find. And for the majority of the documents I've tried
  67. # to manipulate, that I got from throughout the Internet (papers that were
  68. # written using various software), none of these utilities would work properly:
  69. # and wanted to print: sometimes it wouldn't work at all, or it would
  70. # mirror the page, lose font information, or choke in the middle of the
  71. # document (typically near the place some postscript documents was imported
  72. # in the original paper: figure, picture, etc). LPR2 won't replace the
  73. # multipage "n-up" features from the previous utilities (well it could be done,
  74. # but not without a careful study of postscript), but at least it will provide
  75. # a page selection mechanism that works on all reasonable documents: LPR2 has
  76. # never failed on any published document it has been tried with yet (but it
  77. # would be trivial to write some program specifically for lpr2 to fail).
  78. #   This program is NOT a "standalone" postscript interpreter either.
  79. # You still need another PostScript interpreter to get it to work. The
  80. # interpreter is typically just your PostScript printer, or GhostScript,
  81. # or whatever. If you have a non-PostScript printer, the Printing-HOWTO
  82. # (somewhere on all Linux sites) will explain you how to set up "lpr" to
  83. # work with PostScript documents anyway, using GhostScript as the interpreter
  84. # (that's free software).
  85.  
  86. # WHERE TO FIND THE LATEST VERSION
  87. #   The latest version should be available by anonymous ftp:
  88. # * on "ftp://sunsite.unc.edu/pub/Linux/" and mirror linux sites,
  89. #  in subdirectory "system/Printing/"
  90. # * on my own ftp site, "ftp://frmap711.mathp7.jussieu.fr/pub/scratch/rideau/"
  91. #  in subdirectory "lpr2/"
  92. # * if you know any site where people would look for such programs, please
  93. #  tell me, so I can spread this utility.
  94.  
  95. # HOW IT WORKS:
  96. #    The shell part is only a wrapper to accept all the different options.
  97. #    The core of the program (the shell function redefshowpage) prepends some
  98. # PostScript code to the file to print, that redefines "showpage" so that it
  99. # will print every other page. According to the new showpage skipping the
  100. # first page or not, we obtain one document for recto sides, and one another
  101. # for verso sides. We then have to print it all...
  102. #    Note that as the program redefines *global* variables, it cannot be
  103. # recursively called. But as the page selection function is programmable,
  104. # such use isn't needed. If you know how to reliably use local variables
  105. # in postscript, please tell me.
  106. #    There should not be any clash with variables from the postscript file to
  107. # be printed; if however there was one, you can still modify those names in
  108. # the postscript part of lpr2.
  109.  
  110. # INSTALLATION PROCEDURE:
  111. # - gunzip lpr2
  112. # - chmod 0755 lpr2
  113. # - mv lpr2 /somewhere_in_my_PATH/bin/
  114. # - edit the file to customize if need be (look for !!!! marks):
  115. #  the LPR= line should contain the name of a command or function that
  116. #  will print its PostScript standard input. I put "lpr" as the default.
  117. # - Enjoy !
  118.  
  119. # USAGE:
  120. #   To print document "doc.ps", print odd pages on one side and even pages on
  121. # the other.
  122. #
  123. #   My HP LaserJet 4ML printer issues pages in the "right" order, i.e. the
  124. # page on top exits on top. I also have to feed paper with verso (back) upward,
  125. # and top of sheet near me. Thus, I have to print even pages first, then odd
  126. # pages. That's what the default behaviour is.
  127. #
  128. # Rainer Blome (rainer@physik3.gwdg.de) says:
  129. ##   My default `PostScript' printer, an HP LJ III, does emit pages in the
  130. ## `right' order (small page numbers on top), but does not feed verso.  a
  131. ## stack of paper exits the printer exactly the same configuration as it has
  132. ## been put in the paper cassette.
  133. ##   To get the desired result, however, i need the pages in this order, yes,
  134. ## but the empty side has to be in the position that will be printed on.  the
  135. ## HP IV does that automatically, each page is reversed on every printing.
  136. ##   Thus, `print on reverse side' with `emit in right order' is OK, as is
  137. ## `print on topside' with `emit in wrong order'.  other combinations require
  138. ## reordering/reversal by hand.
  139. #
  140. #   If you need some other behaviour, please tell me or correct it and send
  141. # me feedback.
  142. #
  143. #   Beware that there may be one odd page more than even pages. Sheets must be
  144. # fed with verso on top. Default option (--all) does it.
  145. #
  146. #   Thus, the usage is: feed blank sheets to the printer, mark one corner with
  147. # a pencil to see how you will have to feed sheets again to print the other
  148. # side. Then, print even pages. Insert printed pages back into the printer
  149. # in the right order and side, as determined by the pencil, and
  150. # print odd pages.
  151.  
  152. # MISFEATURES:
  153. #   First of all, this is a mixed /bin/sh and Postscript program; the existence
  154. # of such languages is a bug in itself. Please send feedback to God so that
  155. # this state of things changes.
  156. #   Because it uses /bin/sh, this program cannot reliably work with files
  157. # whose name contain spaces, carriage returns, null characters, etc. But this
  158. # is the case for most unix programs, so lpr2 is not *particularly* limiting
  159. # in such sense.
  160. #   There is no soundness testing for the -p option, so beware and stick to
  161. # the syntax; however, an error will most probably result in a run-time error
  162. # at execution of the postscript program, so the document will be rejected
  163. # without any page being printed.
  164.  
  165. # INVOCATION: lpr2 [options] files
  166. #
  167. # option    what it means
  168. # -1,-o,--odd     "print only odd pages"
  169. # -2,-e,--even     "print only even pages"
  170. # -c,--cond    "the string just after this is the postscript condition for
  171. #         a page to be printed, e.g. '4 eq'"
  172. # -s,--select    "print only the page whose number follows '-s' "
  173. # -p,--pages    "print the pages listed after -p
  174. #         in a comma-separated list of the form i-j[%k],
  175. #         where i and j are first and/or last pages,
  176. #         and k is a step. -- not implemented"
  177. # -a,--all    "print even pages; prompt; print odd pages" (default)
  178. # -P,--print    "do send to printer, not to standard output"
  179. # -N,--noprint    "do not send to printer, but to standard output" (default)
  180. # -r,--reverse    "print odd pages; prompt; print even pages in reverse
  181. #         order" (beware: remove last sheet if odd number of pages)
  182. #        NOT IMPLEMENTED YET, and not to be soon, as it involves much
  183. #        more than just a postscript header. Use mpage or psrev (from
  184. #        the psutil package) if you need such thing. Unhappily, those
  185. #        packages are far less reliable than lpr2 v1.2
  186. # -z        define the printing program to be following argument
  187. #        e.g. -z lpr or -z cat
  188. # -Z        following argument is to pass to the printing program
  189. #        e,g, -Z "-lpr_option -second_lpr_option"
  190. # --        stop parsing options: all the remaining arguments are filenames.
  191.  
  192. # THE AUTHOR:
  193. #   I'm no PostScript guru *at all*. It's my first (and certainly last)
  194. # PostScript program. I've never read any Postscript book or official
  195. # documentation or programming recommendation; only gs manpage and
  196. # examples. Postscript looks like a very interesting language to me;
  197. # very FORTH-like indeed. But whoever defined such lame semantics for binding
  198. # only deserves shame.
  199. #   I developped this program under Linux using Ghostscript 2.6.1 in five
  200. # minutes. I've actually spent much more time documenting it and transforming
  201. # it into a shell utility than I did writing the postscript stuff. Just try
  202. # to evaluate and compare the size of the postscript part, the size of the
  203. # shell script part, and the size of the comments ;-)
  204.  
  205. # HOW WELL THE PROGRAM SHOULD BEHAVE:
  206. #   This program works very well for me.
  207. # - you need a shell that supports shell functions (SYSV or SunOS shells do,
  208. # while Ultrix shell doesn't). If yours doesn't work, try getting ksh, bash or
  209. # better even, *zsh* (use option -fy for sh emulation) from the net.
  210. # - The program should work on any well-behaved PostScript document (i.e. the
  211. # kind of documents standard applications produce), but is reported to fail
  212. # when used in combination with some dirty Postscript utilities. mpage by
  213. # Mark P. Hahn 1988 is such dirty program that fails :( :(. Happily, newer
  214. # versions of mpage already support page selection, so when mpage works,
  215. # lpr2 is not needed.
  216. # - You should be able to refeed the printer with its first output, and of
  217. # course, be sure that no one else will use the printer while you are feeding
  218. # the printer with the output for the verso side of the documents.
  219. # - If your printer output pages in the reverse order, you're in for a double
  220. # session of reordering pages :( :( :(
  221.  
  222. # HISTORY:
  223. # version 0.0:  just postcript code manually prepended to a document.
  224. #        developped with ghostscript.
  225. # version 0.1:    the same, but working (with the discovery of erasepage)
  226. # version 1.0:     a script that doesn't even work (I'm ashamed of that)-8
  227. # version 1.1:  the same, but bugs fixed:
  228. #        - cat <<"END" was used instead of cat<<END,
  229. #         and did not expand $1.
  230. #        - %! was forgotten on the first line of the document,
  231. #         which can make auto-detection of file format fail for lpr2
  232. #         documents.
  233. #        - "echo lpr" was also done instead of lpr :(
  234. #        And a new feature added:
  235. #        - if "-" or no file is given, lpr2 will work even with option
  236. #         "--all", by saving input in a file to reread it the second
  237. #         time. Exit and signals are trapped to rm it.
  238. # version 1.1b:    Help was increased thanks to the kind feedback of
  239. #        Warwick Hockley <hock@adhoc.apana.org.au>.
  240. #        Help options are supported.
  241. # version 1.1c: bugs corrected: quotes not closed >8 ; run-time message
  242. #        modified
  243. # version 1.1d: added arbitrary page selection
  244. # version 1.2:    used the ps2ppm PageCount trick using strings to escape
  245. #        save/restore sequences. lpr2 now works with all files
  246. #        I've tried it with !
  247. # version 1.2b:    Just understood why ps2ppm added 1000000 to page count.
  248. #        lpr2 now works after page 9 :)
  249. # version 1.2c:    added nicer page selection: page can be named as p...
  250. # version 1.2d:    merged feedback from Rainer Blome (rainer@physik3.gwgd.de):
  251. #        - removed the -P,--print "I changed my mind. Do print" option
  252. #         because it conflicted with a common printer option.
  253. #        - extended the description of how to reinsert paper.
  254. # version 1.2e:    - added the -p option
  255. #        - replaced the default behavior (print) by printing to stdout
  256. #         if any option is present. Restored option -P, with options
  257. #         -z and -Z to select printing command and default option
  258. #         behavior to "unknown option" instead of passing it blindly
  259. #         to lpr.
  260.  
  261. # TO DO
  262. # - if we know some upper bound to the last page to be printed, put some
  263. # "end execution" Postscript instruction for when this page is reached;
  264. # of course, I should first find how this can in done in PostScript :)
  265.  
  266. # AUTHOR'S .SIGNATURE AND ADDRESSES:
  267. #-    ,                                            ,           _ v    ~  ^  --
  268. #- Fare -- rideau@clipper.ens.fr -- Francois-Rene Rideau -- +)ang-Vu Ban --
  269. #-                                      '                   / .          --
  270. #MOOSE project member. OSL developer.                      |   |   /
  271. #Dreams about The Universal (Distributed) Database.       --- --- //
  272. #Snail mail: 6, rue Augustin Thierry 75019 PARIS FRANCE   /|\ /|\ //
  273. #Phone: 033 1 42026735                                    /|\ /|\ /
  274. #Join the TUNES project for a computing system based on computing freedom !
  275. #           TUNES is a Useful, Not Expedient System
  276. #WWW page at URL: "http://www.eleves.ens.fr:8080/home/rideau/Tunes/"
  277.  
  278.  
  279. ########################## The Postscript stuff ##############################
  280. redefshowpage ()
  281. {
  282. # have as argument condition on page to show
  283. cat <<-END
  284. %!PS-Adobe-3.0
  285.  
  286. /.show.this.page.p { $1 } bind def
  287. /.page.number 1000001 7 string cvs def
  288. /.showpage.orig /showpage load def
  289. /.erasepage /erasepage load def
  290. /.showpage.lpr2 {
  291.    2 dict begin
  292.      /p .page.number dup cvi dup 1 add 3 2 roll cvs pop 1000000 sub def
  293.      mark p
  294.      % (lpr2: showpage called for page ) print dup =only (.\n) print flush
  295.      .show.this.page.p
  296.      /c exch def cleartomark c
  297.    end
  298.      { % (lpr2: showing page.\n) print flush
  299.        .showpage.orig }
  300.      { % (lpr2: skipping page.\n) print flush
  301.        .erasepage }
  302.    ifelse
  303.    % (lpr2: showpage ended.\n) print flush
  304. } def
  305.  
  306. %Redefine showpage...
  307. /showpage { .showpage.lpr2 } bind def
  308.  
  309. END
  310. }
  311.  
  312.  
  313. ########################## The shell functions ##############################
  314. doprinteven ()
  315. {
  316.   (redefshowpage "2 mod 0 eq" ; cat $FILES) | $SENDJOB
  317. }
  318.  
  319. doprintodd ()
  320. {
  321.   (redefshowpage "2 mod 1 eq" ; cat $FILES) | $SENDJOB
  322. }
  323.  
  324. doprintcond ()
  325. {
  326.   (redefshowpage "$COND" ; cat $FILES) | $SENDJOB
  327. }
  328.  
  329. prompt ()
  330. {
  331.   echo "$@" > /dev/tty
  332.   read dummy_answer < /dev/tty
  333. }
  334.  
  335. doall ()
  336. {
  337.   prompt '
  338.   Feed the printer with blank sheets.
  339.   If you don'"'"'t how to feed the printer again to achieve printing on
  340. the "right" side, mark corners of the first sheets with a pencil.
  341.  
  342.   When you'"'"'re done, press "Enter".
  343. '
  344.   doprinteven
  345.   prompt '
  346.   First, do wait for the thing to have been printed.
  347.   When it'"'"'s done, press "Enter".
  348. '
  349.   prompt '
  350.   Now, if your printer issues pages in the wrong order, you have a problem.
  351. You'"'"'ll have to reorder everything twice. Next time, try --reverse option
  352. if it'"'"'s implemented.
  353.  
  354.   The first thing to do after having recovered the back sides of your printed
  355. documents is to ensure that no one else will use the printer while you'"'"'re
  356. printing on the other side.
  357.   When this is done, feed the printer back with the same sheets, but
  358. place the sheets so that the other side will be printed (with the same top
  359. of page). If your document has an odd number of page, add a blank sheet at
  360. the end.
  361.   When you'"'"'re done, press "Enter".
  362. '
  363.   doprintodd
  364. }
  365.  
  366. doreverse ()
  367. {
  368.   echo "NOT IMPLEMENTED YET" >&2
  369.   exit 4
  370. }
  371.  
  372. calllpr ()
  373. {
  374.   $LPR $LPROPTS
  375. }
  376.  
  377. cleanexit () {
  378.   $RM $FILE
  379.   exit 1
  380. }
  381.  
  382.  
  383. ComputeEachCOND () {
  384.   C_COND_0 $1
  385.   COND="$COND1"
  386.   shift
  387.   for i ; do
  388.     C_COND_0 $i
  389.     COND="$COND"'
  390. '"$COND1 or"
  391.   done
  392. }
  393.  
  394. C_COND_0 () {
  395.   case "$1" in
  396.     "-%"*)    : a ; IFS=" -%" ; C_COND_1 1 x $1 ;;
  397.     "-"*"%"*)    : b ; IFS=" -%" ; C_COND_1 1 $1 ;;
  398.     *"-%"*)    : d ; IFS=" -%" ; C_COND_2 $1 ;;
  399.     *"-"*"%"*)    : e ; IFS=" -%" ; C_COND_1 $1 ;;
  400.     "-"*)    : c ; IFS=" -%" ; C_COND_1 1 $1 1 ;;
  401.     *"%"*)    : f ; IFS=" -%" ; C_COND_2 $1 ;;
  402.     *"-")    : g ; IFS=" -%" ; C_COND_1 $1 x 1 ;;
  403.     *"-"*)    : h ; IFS=" -%" ; C_COND_1 $1 1 ;;
  404.     "%"*)    : i ; IFS=" -%" ; C_COND_1 1 x $1 ;;
  405.     *)        : j ; IFS=" -%" ; C_COND_1 $1 $1 1 ;;
  406.   esac
  407. }
  408.  
  409. C_COND_1 () {
  410.   C_COND_n $*
  411. }
  412.  
  413. C_COND_2 () {
  414.   C_COND_m $*
  415. }
  416.  
  417. C_COND_m () {
  418.   C_COND_n $1 x $2
  419. }
  420.  
  421. C_COND_n () {
  422.   IFS=" "
  423.  
  424.   if [ "$1" = "$2" ] ; then
  425.      COND1="p $1 eq"
  426.   else
  427.     if [ "$1" != 1 ] ; then
  428.        COND1="p $1 ge"
  429.        if [ "x$2" != "xx" ] ; then
  430.          COND1="$COND1 p $2 le and"
  431.        fi
  432.     else
  433.       if [ "x$2" != "xx" ] ; then
  434.          COND1="p $2 le"
  435.       else
  436.      COND1=true
  437.       fi
  438.     fi
  439.   fi
  440.   if [ "$3" != 1 ] ; then
  441.      COND1="$COND1 p $1 sub $3 mod 0 eq and"
  442.   fi
  443. }
  444.  
  445.  
  446. ComputeCOND () {
  447.   IFS=" ," ; ComputeEachCOND $1
  448.   IFS=" "
  449. }
  450.  
  451. ######################### The command line interface ########################
  452. LPR="lpr"    # !!!! replace with your standard printing command
  453.         # may be just "cat > /dev/lp1". lpr should be fine.
  454. RM="rm"        # !!!! replace with your standard file deletion command
  455.         # may be "/bin/rm -f -", but rm should be fine.
  456.  
  457. # These should be ok and not need any modification
  458. TODO=doall
  459. LPROPTS=
  460. FILES=
  461. SENDJOB=cat # calllpr
  462.  
  463. ParseOpts () {
  464. GOTOPTS=n
  465. while [ -n "$*" ] ; do
  466.   i="$1" ; shift
  467.   case "$i" in
  468.     -a|--all)    GOTOPTS=y ; TODO=doall ; SENDJOB=calllpr ;;
  469.     -r|--reverse)    GOTOPTS=y ; TODO=doreverse ; SENDJOB=calllpr ;;
  470.     -N|--noprint)    GOTOPTS=y ; SENDJOB=cat ;;
  471.     -P|--print)    GOTOPTS=y ; SENDJOB=calllpr ;;
  472.     -1|-o|--odd)    GOTOPTS=y ; TODO=doprintodd ;;
  473.     -2|-e|--even)    GOTOPTS=y ; TODO=doprinteven ;;
  474.     -c|--cond)    GOTOPTS=y ; TODO=doprintcond ; COND="$1" ; shift ;;
  475.     -s|--select)    GOTOPTS=y ; TODO=doprintcond ; COND="$1 eq" ; shift ;;
  476.     -p|--pages)    GOTOPTS=y ; TODO=doprintcond ; ComputeCOND $1 ; shift ;;
  477.     -z)        GOTOPTS=y ; LPR="$2" ; shift 2 ;;
  478.     -Z)        GOTOPTS=y ; LPROPTS="$LPROPTS $2" ; shift 2 ;;
  479.     --)        FILES="$FILES $*" ; shift $# ;;
  480.  
  481.     -v)        echo "LPR2 v$VERSION" ; exit 0 ;;
  482.     -V|--version)    echo "LPR2 -- version $VERSION" ; exit 0 ;;
  483.     -h|-"?"|--help)    echo "Run command \`\`more $0''" \
  484.                  "for help about this program."
  485.             exit 0 ;;
  486.     -*)        echo "Unknow option \`\`$i''." >&2
  487.             echo "Read file $0 for help." >&2
  488.             exit 3 ;;
  489.     *)        FILES="$FILES $i" ;;
  490.   esac
  491. done
  492. if [ "$GOTOPTS" = "n" ] ; then TODO=doall ; SENDJOB=calllpr ; fi
  493. }
  494.  
  495. DoIt () {
  496.   : '":" is for debugging'
  497.   : LPR=$LPR
  498.   : TODO=$TODO
  499.   : SENDJOB=$SENJOB
  500.   : LPROPTS=$LPROPTS
  501.   : FILES=$FILES
  502.   case "$SENDJOB$TODO$FILES" in
  503.    catdoall*|catdoreverse*)
  504.                 echo "Incompatible options" ;
  505.                 exit 1 ;;
  506.    calllprdoall*" - "*|calllprdoreverse*" - "*|calllprdoall|calllprdoreverse)
  507.                 FILE=/tmp/lpr2-$$
  508.                 trap cleanexit EXIT HUP TERM
  509.                 cat > $FILE
  510.                 FILES=$FILE $FILES
  511.                 $TODO
  512.                 ;;
  513.    *)                $TODO
  514.                 ;;
  515.   esac
  516. }
  517.  
  518. ParseOpts "$@"
  519. DoIt
  520.